/*
 * @[H]:  Copyright (c) 2021 Phytium Information Technology, Inc. 
 * 
 *  SPDX-License-Identifier: Apache-2.0. 
 * 
 * @Date: 2021-08-03 22:49:47
 * @LastEditTime: 2021-08-17 09:37:57
 * @Description:  Description of file
 * @Modify History: 
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */

#include "f_pcie.h"
#include "f_pcie_hw.h"
#include "f_pcie_common.h"
#include "parameters.h"
#include <stdio.h>
#include <string.h>
#include "ft_debug.h"
#define FPCIE_DEBUG_TAG "FPCIE"
#define FPCIE_ERROR(format, ...) FT_DEBUG_PRINT_E(FPCIE_DEBUG_TAG, format, ##__VA_ARGS__)
#define FPCIE_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FPCIE_DEBUG_TAG, format, ##__VA_ARGS__)
#define FPCIE_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FPCIE_DEBUG_TAG, format, ##__VA_ARGS__)
#define FPCIE_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FPCIE_DEBUG_TAG, format, ##__VA_ARGS__)

static u32 FPcieComposeConfigAddress(u8 bus, u8 device, u8 function,
                                     u16 offset)
{
    u32 location = 0;

    location |= ((((u32)bus) << FPCIE_ECAM_BUS_SHIFT) &
                 FPCIE_ECAM_BUS_MASK);

    location |= ((((u32)device) << FPCIE_ECAM_DEV_SHIFT) &
                 FPCIE_ECAM_DEV_MASK);

    location |= ((((u32)function) << FPCIE_ECAM_FUN_SHIFT) &
                 FPCIE_ECAM_FUN_MASK);

    location |= ((((u32)offset) << FPCIE_ECAM_REG_SHIFT) &
                 FPCIE_ECAM_REG_MASK);

    location &= FPCIE_ECAM_MASK;

    return location;
}

static void FPcieReadConfigSpace(FPcie *instance_p, u8 bus, u8 device, u8 function,
                                 u16 offset, u32 *data_p)
{
    u32 location = 0;
    u32 data;

    location = FPcieComposeConfigAddress(bus, device, function, offset);
    data = FPCIE_READREG(instance_p->config.ecam, location);
    *data_p = data;
}

static void FPcieWriteConfigSpace(FPcie *instance_p, u8 bus, u8 device, u8 function,
                                  u16 offset, u32 data)
{
    u32 location = 0;
    u32 reg_value = 0;
    u8 count = 3;
    location = FPcieComposeConfigAddress(bus, device, function, offset);
    FPCIE_WRITEREG(instance_p->config.ecam, location, data);

    do
    {
        reg_value = FPCIE_READREG(instance_p->config.ecam, location);
        if (reg_value == data)
        {
            break;
        }
    } while (count--);
}

static ft_error_t FPcieSkipDevice(FPcie *instance_p, u8 bus, u8 device, u8 function)
{
    u32 config_data;
    u32 pcie_header_type;

    FPcieReadConfigSpace(instance_p, bus, device, function, FPCIE_CFG_CAH_LAT_HD_REG, &config_data);
    pcie_header_type = config_data & FPCIE_CFG_HEADER_TYPE_MASK;

    if ((bus > 0) && (device > 0) && (pcie_header_type == FPCIE_CFG_HEADER_O_TYPE))
    {
        return FPCIE_ERR_TYPE0;
    }

    if ((bus == 0) && (pcie_header_type == FPCIE_CFG_HEADER_O_TYPE))
    {
        return FPCIE_ERR_TYPE0;
    }

    return FT_SUCCESS;
}

static void _DebugShowSize(u64 x)
{
    static const char suffix[][2] = {"", "K", "M", "G", "T"};
    unsigned i;
    if (!x)
        return;
    for (i = 0; i < (sizeof(suffix) / sizeof(*suffix) - 1); i++)
    {
        if (x % 1024)
            break;
        x /= 1024;
    }
    FPCIE_DEBUG_I(" [size=%u%s]", (unsigned)x, suffix[i]);
}

static int FPciePositionRightmostSetbit(u64 size)
{
    int position = 0;
    int bit = 1;

    /* ignore 4 bits */
    size = size & (~(0xf));

    while (!(size & bit))
    {
        bit = bit << 1;
        position++;
    }

    return position;
}

#if defined(__aarch64__)
static u64 FPcieReserveBarMem(FPcie *instance_p, u8 mem_bar_ard_size, u64 size)
{
    u64 ret = 0;

    if (mem_bar_ard_size == FPCIE_BAR_MEM_TYPE_64)
    {
        /* bar地址要与bar size对齐 */
        instance_p->config.pmem_base_addr = ((instance_p->config.pmem_base_addr - 1) | (size - 1)) + 1;
        ret = instance_p->config.pmem_base_addr;
        instance_p->config.pmem_base_addr = instance_p->config.pmem_base_addr + size;
    }
    else
    {
        instance_p->config.npmem_base_addr = ((instance_p->config.npmem_base_addr - 1) | (size - 1)) + 1;
        ret = instance_p->config.npmem_base_addr;
        instance_p->config.npmem_base_addr = instance_p->config.npmem_base_addr + size;
    }

    return ret;
}
#else

static u64 FPcieReserveBarMem(FPcie *instance_p, u8 mem_bar_ard_size, u64 size)
{
    u64 ret = 0;
    (void)mem_bar_ard_size;
    instance_p->config.npmem_base_addr = ((instance_p->config.npmem_base_addr - 1) | (size - 1)) + 1;
    ret = instance_p->config.npmem_base_addr;
    instance_p->config.npmem_base_addr = instance_p->config.npmem_base_addr + size;

    return ret;
}

#endif

/**
 * @name: FPcieIncreamentNpMem
 * @msg: This function increments to next 1Mb page starting position of
 * non prefetchable memory 
 * @param {FPcie} *instance_p is a pointer to the FPcie instance. 
 */
static void FPcieIncreamentNpMem(FPcie *instance_p)
{
    instance_p->config.npmem_base_addr >>= 20;
    instance_p->config.npmem_base_addr++;
    instance_p->config.npmem_base_addr <<= 20;
}

/**
 * @name: FPcieIncreamentNpMem
 * @msg: This function increments to next 1Mb page starting position of
 * prefetchable memory 
 * @param {FPcie} *instance_p is a pointer to the FPcie instance. 
 */
static void FPcieIncreamentPMem(FPcie *instance_p)
{
    instance_p->config.pmem_base_addr >>= 20;
    instance_p->config.pmem_base_addr++;
    instance_p->config.pmem_base_addr <<= 20;
}

static int FPcieAllocBarSpace(FPcie *instance_p, u32 header_type, u8 bus, u8 device, u8 function)
{
    u32 data = 0xffffffff;
    u32 location = 0;
    u32 size = 0, test_write;
    u8 mem_as;
#if defined(__aarch64__)
    u32 location_1 = 0;
    u32 size_1 = 0;
    u64 bar_addr;
    u32 *pptr;

#else
    u32 bar_addr;
#endif
    u32 tmp;
    u8 bar_no;
    u8 max_bars = 0;

    if (header_type == FPCIE_CFG_HEADER_O_TYPE)
    {
        /* for endpoint */
        max_bars = 6;
    }
    else
    {
        /* for bridge */
        max_bars = 2;
    }

    for (bar_no = 0; bar_no < max_bars; bar_no++)
    {
        /* Compose function configuration space location */
        location = FPcieComposeConfigAddress(bus, device, function, FPCIE_CFG_BAR_BASE_OFFSET + bar_no);
        /* Write data to that location */
        FPCIE_WRITEREG(instance_p->config.ecam, location, data);

        size = FPCIE_READREG(instance_p->config.ecam, location);
        if ((size & (~(0xf))) == 0x00)
        {
            /* return saying that BAR is not implemented */
            FPCIE_DEBUG_I("bus: %d, device: %d, function: %d: BAR %d is not implemented ",
                          bus, device, function, bar_no);
            continue;
        }

        /* check for IO space or memory space */
        if (size & FPCIE_CFG_BAR_MEM_TYPE_MASK)
        {
            /* Device required IO address space */
            FPCIE_DEBUG_I("bus: %d, device: %d, function: %d: BAR %d required IO space; it is unassigned ",
                          bus, device, function, bar_no);
            continue;
        }

        /* check for 32 bit AS or 64 bit AS */
        if ((size & 0x06) == 0x04)
        {
            /* 64 bit AS is required */
            mem_as = FPCIE_BAR_MEM_TYPE_64;

#if defined(__aarch64__)

            /* Compose function configuration space location */
            location_1 = FPcieComposeConfigAddress(bus, device, function, FPCIE_CFG_BAR_BASE_OFFSET + (bar_no + 1));

            /* Write data to that location */
            FPCIE_WRITEREG(instance_p->config.ecam, location_1, data);

            /* get next bar if 64 bit address is required */
            // size_1 = FPCIE_READREG(instance_p->config.ecam, location);(location_1);
            size_1 = FPCIE_READREG(instance_p->config.ecam, location_1);

            /* Merge two bars for size */
            pptr = (u32 *)&bar_addr;
            *pptr = size;
            *(pptr + 1) = size_1;

            test_write = FPciePositionRightmostSetbit(bar_addr);

            /* actual bar size is 2 << TestWrite */
            bar_addr = FPcieReserveBarMem(instance_p, mem_as, ((u64)2 << (test_write - 1)));

            tmp = (u32)(bar_addr & 0xFFFFFFFF);
            FPCIE_WRITEREG(instance_p->config.ecam, location, tmp);
            // pcie_write_reg(location, tmp);

            tmp = (u32)(bar_addr >> 32);
            // pcie_write_reg(location_1, tmp);
            FPCIE_WRITEREG(instance_p->config.ecam, location_1, tmp);

            FPCIE_DEBUG_I("bus: %d, device: %d, function: %d: BAR %d, ADDR: %p",
                          bus, device, function, bar_no, (void *)bar_addr);
            _DebugShowSize(((u64)2 << (test_write - 1)));
#else
            test_write = FPciePositionRightmostSetbit(size);

            /* actual bar size is 2 << TestWrite */
            bar_addr =
                FPcieReserveBarMem(instance_p, mem_as,
                                   ((u64)2 << (test_write - 1)));

            tmp = (u32)bar_addr;

            /* Write actual bar address here */
            FPCIE_WRITEREG(instance_p->config.ecam, location, tmp);

            FPCIE_DEBUG_I(
                "bus: %d, device: %d, function: %d: BAR %d, "
                "ADDR: 0x%p size : %dK ",
                bus, device, function, bar_no, (void *)bar_addr,
                ((2 << (test_write - 1)) / 1024));
#endif
        }
        else
        {
            mem_as = FPCIE_BAR_MEM_TYPE_32;

            test_write = FPciePositionRightmostSetbit(size);
            /* actual bar size is 2 << TestWrite */
            bar_addr = FPcieReserveBarMem(instance_p, mem_as, ((u64)2 << (test_write - 1)));

            tmp = (u32)bar_addr;

            /* Write actual bar address here */
            FPCIE_WRITEREG(instance_p->config.ecam, location, tmp);

            FPCIE_DEBUG_I("bus: %d, device: %d, function: %d: BAR %d, ADDR: %p",
                          bus, device, function, bar_no, (void *)bar_addr);
            _DebugShowSize(((u64)2 << (test_write - 1)));
        }

        /* no need to probe next bar if present BAR requires 64 bit AS */
        if ((size & 0x6) == 0x4)
            bar_no = bar_no + 1;
    }

    return FT_SUCCESS;
}

void FPcieFetchDeviceInBus(FPcie *instance_p, u32 bus_num)
{
    u32 config_data = 0;
    static u32 last_bus_num = 0;

    u16 pcie_vender_id;
    u16 pcie_device_id;
    u32 pcie_header_type;
    u32 pcie_multi_fun;

    u32 adr06;
    u32 adr08;
#if defined(__aarch64__)
    u32 adr09;
    u32 adr0a;
    u32 adr0b;
#endif

    int ret;

    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);

    if (bus_num > FT_PCIE_CFG_MAX_NUM_OF_BUS)
    {
        FPCIE_DEBUG_E("bus_num %ld is more than FT_PCIE_CFG_MAX_NUM_OF_BUS ", bus_num);
        return;
    }

    for (u32 pcie_dev_num = 0;
         pcie_dev_num < FT_PCIE_CFG_MAX_NUM_OF_DEV;
         pcie_dev_num++)
    {
        for (u32 pcie_fun_num = 0;
             pcie_fun_num < FT_PCIE_CFG_MAX_NUM_OF_FUN;
             pcie_fun_num++)
        {
            if (FPcieSkipDevice(instance_p, bus_num, pcie_dev_num, pcie_fun_num))
            {
                break;
            }

            /* vendor id*/
            FPcieReadConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_ID_REG, &config_data);
            pcie_vender_id = (u16)(config_data & 0xFFFF);
            pcie_device_id = (u16)((config_data >> 16) & 0xFFFF);

            if (pcie_vender_id == 0xFFFF)
            {
                if (pcie_fun_num == 0)
                    break;
            }
            else
            {
                FPCIE_DEBUG_I(" PCIeBus is %02lX PCIeDev is %02lX PCIeFunc is %02lX ", bus_num, pcie_dev_num, pcie_fun_num);
                FPCIE_DEBUG_I(" Vendor ID is %04X  Device ID is %04X ", pcie_vender_id, pcie_device_id);

                FPcieReadConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_CAH_LAT_HD_REG, &config_data);
                pcie_header_type = config_data & FPCIE_CFG_HEADER_TYPE_MASK;
                pcie_multi_fun = config_data & FPCIE_CFG_MUL_FUN_DEV_MASK;

                if (pcie_header_type == FPCIE_CFG_HEADER_O_TYPE)
                {
                    /* This is an End Point */
                    FPCIE_DEBUG_I("This is an End Point ");

                    /* write address to pcie bar */
                    ret = FPcieAllocBarSpace(instance_p, pcie_header_type, bus_num, pcie_dev_num, pcie_fun_num);

                    if (ret != 0)
                        return;

                    /* initialize this end point and return */
                    FPcieReadConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_CMD_STATUS_REG, &config_data);
                    config_data |= (FPCIE_CFG_CMD_BUSM_EN | FPCIE_CFG_CMD_MEM_EN);

                    FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_CMD_STATUS_REG, config_data);

                    FPcieIncreamentPMem(instance_p);
                    FPcieIncreamentNpMem(instance_p);
                }
                else
                {
                    /* This is an End Point */
                    FPCIE_DEBUG_I("This is a Bridge ");

                    /* alloc bar space and configure bridge */
                    ret = FPcieAllocBarSpace(instance_p, pcie_header_type, bus_num, pcie_dev_num, pcie_fun_num);
                    if (ret != 0)
                        continue;

                    adr06 = 0x0;
                    adr08 = 0x0;
#if defined(__aarch64__)
                    adr09 = 0x0;
                    adr0a = 0x0;
                    adr0b = 0x0;
#endif

                    /* set primary and setcodary bus numbers */
                    adr06 <<= TWO_HEX_NIBBLES;
                    adr06 |= 0xFF;

                    /* sub ordinate bus no 0xF */
                    adr06 <<= TWO_HEX_NIBBLES;
                    adr06 |= (++last_bus_num);

                    /* secondary bus no */
                    adr06 <<= TWO_HEX_NIBBLES;
                    adr06 |= bus_num;
                    FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_BUS_NUMS_T1_REG, adr06);

                    /* Update start values of P and NP MMIO base */
                    adr08 |= ((instance_p->config.npmem_base_addr & 0xFFF00000) >> FOUR_HEX_NIBBLES);
                    FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_NP_MEM_T1_REG, adr08);

#if defined(__aarch64__)
                    if (instance_p->config.pmem_base_addr)
                    {
                        adr09 |= ((instance_p->config.pmem_base_addr & 0xFFF00000) >> FOUR_HEX_NIBBLES);
                        FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_P_MEM_T1_REG, adr09);

                        adr0a |= (instance_p->config.pmem_base_addr >> EIGHT_HEX_NIBBLES);
                        FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_P_UPPER_MEM_T1_REG, adr0a);
                    }
#endif
                    FPcieFetchDeviceInBus(instance_p, last_bus_num);
                    /* update subordinate bus no clearing subordinate bus no */
                    adr06 &= (~(0xFF << FOUR_HEX_NIBBLES));
                    /* setting subordinate bus no */
                    adr06 |= (last_bus_num << FOUR_HEX_NIBBLES);
                    FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_BUS_NUMS_T1_REG, adr06);

                    /*
					* Update end values of MMIO limit
					*/

                    /*
					* Align memory to 1 Mb boundry.
					*
					* eg. 0xE000 0000 is the base address. Increments
					* 1 Mb which gives 0xE010 0000 and writes to limit.
					* So the final value at DW08(in pcie type 1 header)
					* is 0xE010 E000.
					* So the range is 0xE000 0000 to 0xE01F FFFF.
					*
					*/

                    FPcieIncreamentPMem(instance_p);
                    adr08 |= (instance_p->config.npmem_base_addr & 0xFFF00000);
                    FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_NP_MEM_T1_REG, adr08);

#if defined(__aarch64__)
                    FPcieIncreamentNpMem(instance_p);
                    adr09 |= (instance_p->config.pmem_base_addr & 0xFFF00000);
                    FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_P_MEM_T1_REG, adr09);

                    adr0b |= (instance_p->config.pmem_base_addr >> EIGHT_HEX_NIBBLES);
                    FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_P_LIMIT_MEM_T1_REG, adr0b);
#endif

                    /* Increment P & NP mem to next aligned starting address.
					*
					* Eg: As the range is 0xE000 0000 to 0xE01F FFFF.
					* the next starting address should be 0xE020 0000.
					*/
                    FPcieIncreamentPMem(instance_p);
                    FPcieIncreamentNpMem(instance_p);

                    /* Enable configuration */
                    FPcieReadConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_CMD_STATUS_REG, &config_data);

                    config_data |= (FPCIE_CFG_CMD_BUSM_EN | FPCIE_CFG_CMD_MEM_EN);
                    FPcieWriteConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_CMD_STATUS_REG, config_data);
                }
            }

            if ((!pcie_fun_num) && (!pcie_multi_fun))
            {
                /*
				* If it is function 0 and it is not a
				* multi function device, we don't need
				* to look any further on this devie
				*/
                break;
            }
        }
    }
}

static u64 FPcieGetBarSpace(FPcie *instance_p, u8 bus, u8 device, u8 function, u32 bar_no)
{
    u32 location = 0, location_1 = 0;
    u64 addr0 = 0, addr1 = 0;
    u64 bar_addr;
    u32 type;

    /* Compose function configuration space location */
    location = FPcieComposeConfigAddress(bus, device, function, FPCIE_CFG_BAR_BASE_OFFSET + (bar_no & ~(1)));

    type = FPCIE_READREG(instance_p->config.ecam, location);
    type = type & 0xf;

    if ((type & 0x06) != 0x04)
    {
        location = FPcieComposeConfigAddress(bus, device, function, FPCIE_CFG_BAR_BASE_OFFSET + bar_no);

        type = FPCIE_READREG(instance_p->config.ecam, location);
        type = type & 0xf;
    }

    /* check for IO space or memory space */
    if (type & FPCIE_CFG_BAR_MEM_TYPE_MASK)
    {
        /* Device required IO address space */
        FPCIE_DEBUG_I("bus: %d, device: %d, function: %d: BAR %ld required IO space; it is unassigned",
                      bus, device, function, bar_no);
        return 0;
    }

    /* check for 32 bit AS or 64 bit AS */
    if ((type & 0x06) == 0x04)
    {
        bar_no = (bar_no & ~(1));

        /* Compose function configuration space location */
        location = FPcieComposeConfigAddress(bus, device, function, FPCIE_CFG_BAR_BASE_OFFSET + (bar_no));
        addr0 = FPCIE_READREG(instance_p->config.ecam, location);
        addr0 &= ~0xf;

        location_1 = FPcieComposeConfigAddress(bus, device, function, FPCIE_CFG_BAR_BASE_OFFSET + (bar_no + 1));
        addr1 = FPCIE_READREG(instance_p->config.ecam, location_1);

        bar_addr = (addr0 & 0xffffffff) | (addr1 << 32);

        FPCIE_DEBUG_I("bus: %d, device: %d, function: %d: BAR %ld, ADDR: %llx",
                      bus, device, function, bar_no, bar_addr);

        return bar_addr;
    }
    else
    {
        location = FPcieComposeConfigAddress(bus, device, function, FPCIE_CFG_BAR_BASE_OFFSET + (bar_no));
        addr0 = FPCIE_READREG(instance_p->config.ecam, location);
        addr0 &= ~0xf;

        bar_addr = addr0;

        FPCIE_DEBUG_I("bus: %d, device: %d, function: %d: BAR %ld, ADDR: %llx",
                      bus, device, function, bar_no, bar_addr);

        return bar_addr;
    }

    return 0;
}

u64 FPcieFindBusDeviceBarAddress(FPcie *instance_p, FpcieId *check_id_p, u32 bus_num, u32 bar)
{
    u32 config_data = 0;
    u16 pcie_vender_id;
    u16 pcie_device_id;
    u32 pcie_header_type;
    u32 pcie_multi_fun;
    u32 pcie_dev_num = 0;
    u32 pcie_fun_num = 0;

    for (pcie_dev_num = 0; pcie_dev_num < FT_PCIE_CFG_MAX_NUM_OF_DEV; pcie_dev_num++)
    {
        for (pcie_fun_num = 0; pcie_fun_num < FT_PCIE_CFG_MAX_NUM_OF_FUN; pcie_fun_num++)
        {
            if (FPcieSkipDevice(instance_p, bus_num, pcie_dev_num, pcie_fun_num))
            {
                break;
            }

            /* vendor id*/
            FPcieReadConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_ID_REG, &config_data);
            pcie_vender_id = (u16)(config_data & 0xFFFF);
            pcie_device_id = (u16)((config_data >> 16) & 0xFFFF);

            if (pcie_vender_id == 0xFFFF)
            {
                if (pcie_fun_num == 0)
                    break;
            }
            else
            {
                FPcieReadConfigSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, FPCIE_CFG_CAH_LAT_HD_REG, &config_data);
                pcie_header_type = config_data & FPCIE_CFG_HEADER_TYPE_MASK;
                pcie_multi_fun = config_data & FPCIE_CFG_MUL_FUN_DEV_MASK;

                if (pcie_header_type == FPCIE_CFG_HEADER_O_TYPE)
                {
                    if (pcie_vender_id == check_id_p->vendor && pcie_device_id == check_id_p->device)
                    {
                        return FPcieGetBarSpace(instance_p, bus_num, pcie_dev_num, pcie_fun_num, bar);
                    }
                }
            }

            if ((!pcie_fun_num) && (!pcie_multi_fun))
            {
                /*
				* If it is function 0 and it is not a
				* multi function device, we don't need
				* to look any further on this devie
				*/
                break;
            }
        }
    }
    return 0ULL;
}

ft_error_t FPcieCfgInitialize(FPcie *instance_p, FPcieConfig *config_p)
{
    fsize_t i;

    /* Assert arguments */
    FT_ASSERTNONVOID(instance_p != NULL);
    FT_ASSERTNONVOID(config_p != NULL);

    /* Clear instance memory and make copy of configuration */
    memset(instance_p, 0, sizeof(FPcie));
    memcpy(&instance_p->config, config_p, sizeof(FPcieConfig));

    instance_p->is_ready = FT_COMPONENT_IS_READY;

    /* Disable all interrupts */
    FPcieMiscIrqClear(instance_p, FPCIE_PEU0_C0);
    FPcieMiscIrqClear(instance_p, FPCIE_PEU0_C1);
    FPcieMiscIrqClear(instance_p, FPCIE_PEU0_C2);
    FPcieMiscIrqClear(instance_p, FPCIE_PEU1_C0);
    FPcieMiscIrqClear(instance_p, FPCIE_PEU1_C1);
    FPcieMiscIrqClear(instance_p, FPCIE_PEU1_C2);

    for (i = 0; i <= FPCIE_PEU1_C2; i++)
    {
        /* code */
        FPcieEpCleanBar(instance_p, i, FPCIE_BAR_0);
        FPcieEpCleanBar(instance_p, i, FPCIE_BAR_1);
        FPcieEpCleanBar(instance_p, i, FPCIE_BAR_2);
        FPcieEpCleanBar(instance_p, i, FPCIE_BAR_3);
        FPcieEpCleanBar(instance_p, i, FPCIE_BAR_4);
        FPcieEpCleanBar(instance_p, i, FPCIE_BAR_5);
    }

    return (FT_SUCCESS);
}
